<!DOCTYPE html>
<html ng-app="minimal">
<head>
<title>Minimal GoJS Sample with AngularJS</title>
<meta name="description" content="Interactive diagram implemented by GoJS using AngularJS, including a diagram directive and model binding." />
<!-- Copyright 1998-2016 by Northwoods Software Corporation. -->
<meta charset="UTF-8">
<script src="go.js"></script>
<link href="../assets/css/goSamples.css" rel="stylesheet" type="text/css" />  <!-- you don't need to use this -->
<script src="goSamples.js"></script>  <!-- this is only for the GoJS Samples framework -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.2/angular.min.js"></script>
<script id="code">
  angular.module('minimal', [])
    .directive('goDiagram', function() {
      return {
        restrict: 'E',
        template: '<div></div>',  // just an empty DIV element
        replace: true,
        scope: { model: '=goModel' },
        link: function(scope, element, attrs) {
          var $ = go.GraphObject.make;
          var diagram =  // create a Diagram for the given HTML DIV element
            $(go.Diagram, element[0],
              {
                nodeTemplate: $(go.Node, "Auto",
                                { locationSpot: go.Spot.Center },
                                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                                $(go.Shape, "RoundedRectangle", new go.Binding("fill", "color"),
                                  {
                                    portId: "", cursor: "pointer",
                                    fromLinkable: true, toLinkable: true,
                                    fromLinkableSelfNode: true, toLinkableSelfNode: true,
                                    fromLinkableDuplicates: true, toLinkableDuplicates: true
                                  }),
                                $(go.TextBlock, { margin: 3, editable: true },
                                  new go.Binding("text", "name").makeTwoWay())
                              ),
                linkTemplate: $(go.Link,
                                { relinkableFrom: true, relinkableTo: true },
                                $(go.Shape),
                                $(go.Shape, { toArrow: "OpenTriangle" })
                              ),
                initialContentAlignment: go.Spot.Center,
                "ModelChanged": updateAngular,
                "undoManager.isEnabled": true
              });

          // whenever a GoJS transaction has finished modifying the model, update all Angular bindings
          function updateAngular(e) {
            if (e.isTransactionFinished) scope.$apply();
          }

          // notice when the value of "model" changes: update the Diagram.model
          scope.$watch("model", function(newmodel) {
            var oldmodel = diagram.model;
            if (oldmodel !== newmodel) {
              diagram.removeDiagramListener("ChangedSelection", updateSelection);
              diagram.model = newmodel;
              diagram.addDiagramListener("ChangedSelection", updateSelection);
            }
          });

          scope.$watch("model.selectedNodeData.name", function(newname) {
            if (!diagram.model.selectedNodeData) return;
            // disable recursive updates
            diagram.removeModelChangedListener(updateAngular);
            // change the name
            diagram.startTransaction("change name");
            // the data property has already been modified, so setDataProperty would have no effect
            var node = diagram.findNodeForData(diagram.model.selectedNodeData);
            if (node !== null) node.updateTargetBindings("name");
            diagram.commitTransaction("change name");
            // re-enable normal updates
            diagram.addModelChangedListener(updateAngular);
          });

          // update the model when the selection changes
          function updateSelection(e) {
            var selnode = diagram.selection.first();
            diagram.model.selectedNodeData = (selnode instanceof go.Node ? selnode.data : null);
            scope.$apply();
          }
          diagram.addDiagramListener("ChangedSelection", updateSelection);
        }
      };
    })
    .controller('MinimalCtrl', function($scope) {
      $scope.model = new go.GraphLinksModel(
        [
          { key: 1, name: "Alpha", color: "lightblue" },
          { key: 2, name: "Beta", color: "orange" },
          { key: 3, name: "Gamma", color: "lightgreen" },
          { key: 4, name: "Delta", color: "pink" }
        ],
        [
          { from: 1, to: 2 },
          { from: 1, to: 3 },
          { from: 2, to: 2 },
          { from: 3, to: 4 },
          { from: 4, to: 1 }
        ]);

      $scope.model.selectedNodeData = null;

      $scope.replaceModel = function() {
        $scope.model = new go.GraphLinksModel(
            [
              { key: 11, name: "zeta", color: "red" },
              { key: 12, name: "eta", color: "green" }
            ],
            [
              { from: 11, to: 12 }
            ]
          );
      }
    });
</script>
</head>
<body ng-controller="MinimalCtrl"
      onload="if (window.goSamples) goSamples()"> <!-- only needed for the goSamples framework -->
<div id="sample">
  <!-- a go-diagram element referring to the model, originally written as: -->
  <!-- &lt;go-diagram go-model="model" style="border: solid 1px blue; width:100%; height:400px"&gt;&lt;/go-diagram&gt; -->
  <go-diagram go-model="model" style="border: solid 1px blue; width:100%; height:400px"></go-diagram>
  Number of node data: {{model.nodeDataArray.length}}
  <br />
  Alpha node location: {{model.findNodeDataForKey(1).loc}}
  <br />
  Selected node: {{model.selectedNodeData.key}}  <input type="text" ng-model="model.selectedNodeData.name"></input>
  <br />
  Number of link data: {{model.linkDataArray.length}}
  <p>
  This defines an <a href="https://angularjs.org/">AngularJS</a> directive for creating a <b>GoJS</b> <a>Diagram</a> with certain properties.
  It also sets up a controller holding a <a>GraphLinksModel</a> that is passed
  to the <b>go-diagram</b> element via the <b>go-model</b> attribute.
  </p>
  <p>
  Note that the above bindings are updated automatically as the user moves the "Alpha" node,
  copies or deletes Parts in the Diagram, reconnects the Link from "Alpha" to "Beta", or performs an undo or redo.
  </p>
  <p>
  You can also replace the <a>Diagram.model</a> just by setting the "model" property on the $scope,
  since the "goDiagram" directive watches that property for changes.
  </p>
  <button ng-click="replaceModel()">Replace Model</button>
  <p>
  Please note that the source code shown here for the HTML shows the expanded DIV element produced by AngularJS and other modified elements,
  not <code>&lt;go-diagram go-model="model" style=...&gt;&lt;/go-diagram&gt;</code> and &#123; &#123; &#125; &#125; bindings as originally written.
  </p>
</div>
</body>
</html>